// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef VIDEOENCODER_H
#define VIDEOENCODER_H
#include <unistd.h>
#include <atomic>
#include <queue>
#include <functional>
#include "VideoEngine.h"
#include "VideoEncoderParam.h"
#include "Include/msghead.h"
#include "MemoryManagement/VmiBuffer.h"
#include "Communication/StreamParse/StreamParser.h"
#include "Log/logging.h"
#include "Communication/Include/CommApi.h"
#include "Communication/PacketManager.h"

enum ENCODER_RECV_STATUS {
    ENCODER_RECEIVE_INIT  = 1,
    ENCODER_RECEIVE_RUNNING  = 2,
    ENCODER_RECEIVE_STOP = 3
};

// 远端收到的YUV或配置数据
struct VideoData {
    VMIMsgType dataType {VMIMsgType::Invalid};
    uint8_t* data {nullptr};
    uint32_t dataLength {0};

    VideoData() = default;
    VideoData(VMIMsgType dataType, uint8_t* data, uint32_t dataLength) {
        this->dataType = dataType;
        this->data = data;
        this->dataLength = dataLength;
    }
};

class VideoEncoder {
public:

    /**
     * @功能描述：构造函数
     */
    VideoEncoder(std::function<void()> fnCallback);
    /**
     * @功能描述：析构函数
     */
    ~VideoEncoder() ;

    /**
     * @功能描述：初始化编码引擎、注册回调、启动编码
     */
    bool Start();

    /**
     * @功能描述：销毁编码引擎
     */
    void ForceStop();

    /**
     * @功能描述：调用编码引擎进行编码
     */
    void Handle(uint8_t* packet, uint32_t len);
    
    /**
     * @功能描述：调用编码引擎进行补帧
     */
    void HandleRepeat();

    /**
     * @功能描述：解析云机侧编码Cjson参数
     */
    bool ParseCjsonConfig(std::string conf, VideoEncoderParam& videoEncoderParam);

    /**
     * @功能描述：设置编码器初始化参数
     * @参数 [in] packet：接收数据地址
     * @参数 [in] len:接收数据长度
     *
     */
    void InitEncodeParam(uint8_t *packet, uint32_t len);
private:
    std::mutex m_queueLock = {};
    std::mutex m_lastFrameLock = {};
    std::function<void()> m_callback = nullptr;
    VideoEngine *m_videoEngine = nullptr;
    EngineStat m_status = EngineStat::VMI_ENCODE_ENGINE_EXIT;
    VideoEncoderParam m_param = {};
    std::thread *m_recvTask = nullptr;
    std::thread *m_encodeTask = nullptr;
    std::atomic<bool> m_recvFlag = {false};
    std::atomic<bool> m_encodeFlag = {false};
    std::atomic<ENCODER_RECV_STATUS> m_recvStatus{ENCODER_RECV_STATUS::ENCODER_RECEIVE_INIT};
    uint8_t m_orienTation = 0;
    uint8_t m_keyFrame = 0;
    int m_rcMode = 0;
    uint64_t m_repeatDataStartTs = 0;
    uint64_t m_repeatDataEndTs = 0;
    uint64_t m_lastFrameEncodeTs = 0;
    // YUV和参数配置在同一个队列
    std::queue<VideoData> m_encodeQueue;
    std::pair<uint8_t*, uint32_t> m_lastFrame = std::pair<uint8_t*, uint32_t>(nullptr, 0);
    // m_encodeQueue队列中的YUV帧数量
    uint32_t m_YUVCount = 0;

    void UpdateLastFrameData(std::pair<uint8_t*, uint32_t> &yuvData);
    bool CanDoRepeat();
    void ClearLastFrame();
    bool IsLastFrameNotReady();
    void AddVideoDataToQueue(VideoData &videoData);
    size_t GetEncodeQueueYUVCount();
    VideoData PopEncodeQueue();
    void ClearEncodeQueue();
    void DestroyVideoEngine();
    bool IsQueueEmpty();

    /**
     * @功能描述：编码引擎回调函数
     */
    static int SendFrame(uint8_t *data, int length, VideoParamExt& param);
    /*
     * @功能描述: 向云机侧回传错误码函数
     * @参数 [in] errorCode: 错误码
     */
    static int SendErrorCode(uint8_t errorCode);
    /*
     * @功能描述: 接收待编码数据线程
     * @参数 [in] videoEncoder：编码器
     */
    friend void RcvTaskentry(VideoEncoder *videoEncoder);
    /*
     * @功能描述: 编码线程
     * @参数 [in] videoEncoder：编码器
     */
    friend void EncodeTaskentry(VideoEncoder *videoEncoder);
    /*
     * @功能描述: 补帧线程
     * @参数 [in] videoEncoder：编码器
     */
    friend void RepeatTaskEntry(VideoEncoder* videoEncoder);
};

#endif
